pub mod field;
pub mod index;
pub mod query;
pub mod relation;
/// 相关工具
pub mod tools;
/// 各数据验证类型定义
pub mod types;

use std::str::FromStr;

use crate::err::OrmError;
use crate::model::relation::JoinInfo;

use self::field::Field;
use self::index::Index;
use self::query::expr::{LeftExprInfo, QueryExpr};
use self::query::method::QueryMethod;
use self::query::QueryBuilder;
use self::relation::JoinBaseTableInfo;
use super::err::OrmResult;

/// 最大支持10个外键
pub trait Model {
    /// 表定义信息
    const META: Meta;
    /// 表主键字段类型
    type PkType;
    /// 外键模型1
    type FkModel1: Model;
    /// 外键模型2
    type FkModel2: Model;
    /// 外键模型3
    type FkModel3: Model;
    /// 外键模型4
    type FkModel4: Model;
    /// 外键模型5
    type FkModel5: Model;
    /// 外键模型6
    type FkModel6: Model;
    /// 外键模型7
    type FkModel7: Model;
    /// 外键模型8
    type FkModel8: Model;
    /// 外键模型9
    type FkModel9: Model;
    /// 外键模型10
    type FkModel10: Model;

    /// 解析左边表达式
    ///
    /// # 参数说明
    ///
    /// * field_index 字段索引
    /// * join_base_table_info 当前表为被链接的表，对应的上级表信息
    ///
    /// # 返回说明
    ///
    /// 解析出的字段信息，表格信息，join信息
    fn db_parse_left(
        field_index: u8,
        join_base_table_info: Option<JoinBaseTableInfo>,
    ) -> OrmResult<LeftExprInfo> {
        let mut sql_fields: Vec<(Field, String)> = Vec::new();
        let mut expr_method = QueryMethod::default();
        let mut joins: Vec<JoinInfo> = Vec::new();

        // 当前解析的表名称
        let cur_table_name: String = if let Some(join_base_table_info) = &join_base_table_info {
            // 将当前表添加进join记录中
            // 生成join语句,其中join表重命名为外键字段名称_外键表名称

            // 当前表为上级表的join表，在表名称前添加上级表对应外键的名称_
            let join_table_name = format!(
                "{}_{}",
                join_base_table_info.link_field_name,
                Self::META.table_name
            );
            let join_pk = Self::META
                .get_pk()
                .ok_or(OrmError::MissPkTable(format!("join表{}无主键", Self::META.table_name)))?;

            let join_sql = format!(
                "JOIN {} AS {} ON {}.{} = {}.{}",
                Self::META.table_name,
                join_table_name,
                join_base_table_info.base_table_name,
                join_base_table_info.link_field_table_name,
                join_table_name,
                join_pk.table_field_name
            );

            let join_info = JoinInfo {
                meta: Self::META,
                join_table_name:join_table_name.clone(),
                join_sql,
            };
            joins.push(join_info);
            join_table_name
        } else {
            Self::META.table_name.into()
        };

        // 表达式分隔符
        let expr_separator = "__";
        // 表达式各项目列表
        let expr_items: Vec<_> = field_index.split(expr_separator).collect();
        // 步骤 1 : 解析第一个项目
        let first_item = expr_items[0];
        if let Some(field) = &Self::META.get_field(first_item) {
            // 为字段
            // 保存字段信息和对应sql信息
            sql_fields.push((
                field.to_owned().clone(),
                format!("{cur_table_name}.{}", field.table_field_name),
            ));
            // 有后续表达式项目，判断是否方法和外键
            if expr_items.len() > 1 {
                // 第二个项目
                let second_item = expr_items[1];
                // 第二个项目为方法
                if let Ok(first_method) = QueryMethod::from_str(second_item) {
                    // 为字段查询方法
                    expr_method = first_method;
                    // 方法后续还有二级方法
                    if expr_items.len() > 2 {
                        // 第三个项目
                        let third_item = expr_items[2];
                        // 解析第三个项目，判断对应是否为方法
                        if let Ok(second_method) = QueryMethod::from_str(third_item) {
                            // 第三个项目为方法，判断是否日期、时间类方法
                            // 判断第二个项目是否为日期或者时间类方法
                            if expr_method.is_date_method() && second_method.is_date_sub_method() {
                                // 合法的主方法和二级方法
                                // 生成新包含二级方法的一级方法
                                expr_method = match expr_method {
                                    QueryMethod::Date(_) => {
                                        QueryMethod::Date(Box::new(second_method))
                                    }
                                    QueryMethod::Month(_) => {
                                        QueryMethod::Month(Box::new(second_method))
                                    }
                                    QueryMethod::Year(_) => {
                                        QueryMethod::Year(Box::new(second_method))
                                    }
                                    QueryMethod::Week(_) => {
                                        QueryMethod::Week(Box::new(second_method))
                                    }
                                    QueryMethod::WeekDay(_) => {
                                        QueryMethod::WeekDay(Box::new(second_method))
                                    }
                                    QueryMethod::Quarter(_) => {
                                        QueryMethod::Quarter(Box::new(second_method))
                                    }
                                    QueryMethod::Time(_) => {
                                        QueryMethod::Time(Box::new(second_method))
                                    }
                                    QueryMethod::Hour(_) => {
                                        QueryMethod::Hour(Box::new(second_method))
                                    }
                                    QueryMethod::Minute(_) => {
                                        QueryMethod::Minute(Box::new(second_method))
                                    }
                                    QueryMethod::Second(_) => {
                                        QueryMethod::Second(Box::new(second_method))
                                    }
                                    _ => unreachable!(),
                                };
                            } else {
                                // 左边表达式有误,第一个项目必须为表字段
                                return Err(OrmError::IncorrectQueryMethod(format!(
                                    "表达式解析错误：第三级错误，查询方法后续查询项目只能为日期、时间类查询方法：{}",
                                    field_index
                                )));
                            }
                        } else {
                            // 左边表达式有误,第一个项目必须为表字段
                            return Err(OrmError::IncorrectQueryMethod(format!(
                                "表达式解析错误：第三级错误，查询方法后续查询项目只能为日期、时间类查询方法：{}",
                                field_index
                            )));
                        }
                    }
                } else if let Some(fk_no) = &field.fk_model_no {
                    // 第一个字段为外键，且后续还有项目，读取外键表信息
                    // 从第二个项目开始重新构建左表达式，用于外键类型生成表达式信息
                    let left_remain = &expr_items[1..expr_items.len()].join(expr_separator);
                    // 连接表名称需要包含上级表对应字段名称
                    let link_field_name = if let Some(join_base_table_info) = &join_base_table_info {
                        format!("{}_{}",join_base_table_info.link_field_name,field.name)
                    }else{
                        field.name.into()
                    };
                    let join_base_info = JoinBaseTableInfo {
                        base_table_name:&cur_table_name,
                        link_field_name:&link_field_name,
                        link_field_table_name:field.table_field_name
                    };
                    // 后续为外链表字段，调用对应类型的db_parse_left获取后续解析结果
                    let mut join_expr_info = match fk_no {
                        field::FkNo::One => Self::FkModel1::db_parse_left(
                            left_remain,
                            Some(join_base_info),
                        ),
                        field::FkNo::Two => Self::FkModel2::db_parse_left(
                            left_remain,
                            Some(join_base_info),
                        ),
                        field::FkNo::Three => Self::FkModel3::db_parse_left(
                            left_remain,
                            Some(join_base_info),
                        ),
                        field::FkNo::Four => Self::FkModel4::db_parse_left(
                            left_remain,
                            Some(join_base_info),
                        ),
                        field::FkNo::Five => Self::FkModel5::db_parse_left(
                            left_remain,
                            Some(join_base_info),
                        ),
                        field::FkNo::Six => Self::FkModel6::db_parse_left(
                            left_remain,
                            Some(join_base_info),
                        ),
                        field::FkNo::Seven => Self::FkModel7::db_parse_left(
                            left_remain,
                            Some(join_base_info),
                        ),
                        field::FkNo::Eight => Self::FkModel8::db_parse_left(
                            left_remain,
                            Some(join_base_info),
                        ),
                        field::FkNo::Night => Self::FkModel9::db_parse_left(
                            left_remain,
                            Some(join_base_info),
                        ),
                        field::FkNo::Ten => Self::FkModel10::db_parse_left(
                            left_remain,
                            Some(join_base_info),
                        ),
                    }?;
                    // 将当期join信息与下级join信息合并，并将下级解析结果作为当前解析结果返回
                    joins.extend(join_expr_info.joins);
                    join_expr_info.joins=joins;
                    return Ok(join_expr_info)
                } else {
                    // 表达式错误
                    return Err(OrmError::IncorrectQueryMethod(format!(
                        "表达式解析错误：第二级查询方法错误：{}",
                        field_index
                    )));
                }
            }
        } else {
            // 第一个项目表达式错误
            return Err(OrmError::IncorrectQueryMethod(format!(
                "表达式解析错误：首个表达式项目必须为表字段{}",
                field_index
            )));
        }

        // 只取最后字段
        let (field, field_sql) = sql_fields.pop().expect("提取query sql字段信息");
        Ok(LeftExprInfo {
            field,
            field_sql,
            joins,
            method: expr_method,
        })
    }

    /// 获取多个
    fn db_filter(expr: QueryExpr) -> OrmResult<QueryBuilder> {
        let mut wheres: Vec<String> = Vec::new();
        let mut joins: Vec<JoinInfo> = Vec::new();
        let mut selects: Vec<String> = Vec::new();
        match expr {
            QueryExpr::And { left, right } => {
                let QueryBuilder {
                    wheres: left_wheres,
                    joins: left_joins,
                    select_fields: left_selects,
                    ..
                } = Self::db_filter(*left)?;
                let QueryBuilder {
                    wheres: right_wheres,
                    joins: right_joins,
                    select_fields: right_selects,
                    ..
                } = Self::db_filter(*right)?;
                let sql = format!(
                    "( {} AND {} )",
                    left_wheres.join("\n"),
                    right_wheres.join("\n")
                );
                wheres.push(sql);
                joins.extend(left_joins);
                joins.extend(right_joins);
                selects.extend(left_selects);
                selects.extend(right_selects);
            }
            QueryExpr::Or { left, right } => {
                let QueryBuilder {
                    wheres: left_wheres,
                    joins: left_joins,
                    select_fields: left_selects,
                    ..
                } = Self::db_filter(*left)?;
                let QueryBuilder {
                    wheres: right_wheres,
                    joins: right_joins,
                    select_fields: right_selects,
                    ..
                } = Self::db_filter(*right)?;
                let sql = format!(
                    "( {} OR {} )",
                    left_wheres.join("\n"),
                    right_wheres.join("\n")
                );
                wheres.push(sql);
                joins.extend(left_joins);
                joins.extend(right_joins);
                selects.extend(left_selects);
                selects.extend(right_selects);
            }
            QueryExpr::Item { field_index, right,join,method } => {
            QueryExpr::Item { field_index, right,join,method } => {
                let left_info = Self::db_parse_left(field_index, None)?;
                joins.extend(left_info.joins);
                let sql = left_info
                    .method
                    .to_sql_for_value(&left_info.field, &left_info.field_sql, right)?;
                wheres.push(sql)
            }
            QueryExpr::Not { left, right } => {
                let left_info = Self::db_parse_left(left, None)?;
                joins.extend(left_info.joins);
                let sql = format!(
                    "NOT {}",
                    left_info
                        .method
                        .to_sql_for_value(&left_info.field, &left_info.field_sql, right)?
                );
                wheres.push(sql)
            }
        }
        // 去除重复的join
        joins.sort_by(|a, b| a.join_table_name.cmp(&b.join_table_name));
        joins.dedup_by(|a, b| a.join_table_name.eq(&b.join_table_name));
        
        Ok(QueryBuilder {
            base_meta: Self::META,
            select_fields: selects,
            wheres,
            joins,
        })
    }
    /// 获取1个
    fn db_get() {
        unimplemented!()
    }
    /// 保存到数据库
    fn db_save() {
        unimplemented!()
    }
    /// 从数据库删除
    fn db_delete() {
        unimplemented!()
    }
}

/// 表元数据
#[derive(Debug)]
pub struct Meta {
    /// 对应数据库表名称
    pub table_name: &'static str,
    /// 表字段清单
    pub field_list: &'static [Field],
    /// 索引清单
    pub index_list: Option<&'static [Index]>,
}
impl Meta {
    /// 通过字段名称获取对应字段信息
    ///
    /// * name 要获取的字段名称，必须与struct定义完全一致
    pub fn get_field(&self, name: &str) -> Option<&Field> {
        self.field_list.iter().find(|field| field.name == name)
    }
    /// 获取主键
    pub fn get_pk(&self) -> Option<&Field> {
        self.field_list.iter().find(|field| field.pk)
    }
}

/// 无外键时使用()作为外键类型
impl Model for () {
    const META: Meta = Meta {
        table_name: "",
        field_list: &[],
        index_list: None,
    };

    type PkType = ();

    type FkModel1 = Self;

    type FkModel2 = Self;

    type FkModel3 = Self;

    type FkModel4 = Self;

    type FkModel5 = Self;

    type FkModel6 = Self;

    type FkModel7 = Self;

    type FkModel8 = Self;

    type FkModel9 = Self;

    type FkModel10 = Self;
}
